package bll

import (
	log "auth/collector/logger"
	"auth/errors"
	"auth/event"
	"auth/model"
	"auth/model/entity"
	"auth/store"
	"auth/store/postgres"
	"gorm.io/gorm"
	"time"
)

type menu struct {
	iMenu          store.IMenu
	iAuthorityMenu store.IAuthorityMenu
	iAuthority     store.IAuthority
	iUserAuthority store.IUserAuthority
}

var Menu = &menu{}

func (a *menu) init() func() {
	a.iMenu = postgres.Menu
	a.iAuthorityMenu = postgres.AuthorityMenu
	a.iAuthority = postgres.Authority
	a.iUserAuthority = postgres.UserAuthority
	return func() {}
}
func (a *menu) onEvent(*event.Data) {}

func (a *menu) GetMenu(userId int64) (*model.GetMenuListResponse, error) {
	var (
		err               error
		out               = &model.GetMenuListResponse{}
		authorityMenuList []*entity.AuthorityMenu
		userAuthorityList []*entity.UserAuthority
	)
	//获取角色ids
	userAuthorityList, err = a.iUserAuthority.FindByUserId(userId)
	if err != nil && errors.Is(gorm.ErrRecordNotFound, err) {
		log.Error("获取角色失败!", err)
		return nil, err
	}
	var authorityIds []int64
	for i := range userAuthorityList {
		authorityIds = append(authorityIds, userAuthorityList[i].AuthorityId)
	}
	//获取角色菜单
	if authorityMenuList, err = a.iAuthorityMenu.FindByAuthorityIds(authorityIds); err != nil {
		log.Error("获取角色菜单失败!", err)
		return nil, err
	}
	var menuIds []int64
	for i := range authorityMenuList {
		menuIds = append(menuIds, authorityMenuList[i].MenuId)
	}
	menuMenuInfoList, err := getMenuListByMenuIds(menuIds)
	if err != nil {
		return nil, err
	}
	out.Data = menuMenuInfoList
	return out, err
}

func (a *menu) GetMenuList(in *model.MenuListRequest) (*model.MenuListResponse, error) {
	var (
		err     error
		total   int
		out     = &model.MenuListResponse{}
		treeMap = make(map[int64][]*model.MenuInfo)
	)
	treeMap, err = getMenuTreeMap()
	if err != nil {
		log.Error("GetMenuList error", err)
		return nil, err
	}
	menuMenuInfoList := treeMap[0]
	for i := 0; i < len(menuMenuInfoList); i++ {
		err = getBaseChildrenList(menuMenuInfoList[i], treeMap)
	}
	out.Total = total
	out.Data = menuMenuInfoList
	return out, err
}

func (a *menu) GetBaseMenuTree() (*model.SysBaseMenusResponse, error) {
	var (
		err     error
		out     = &model.SysBaseMenusResponse{}
		treeMap = make(map[int64][]*model.MenuInfo)
	)
	treeMap, err = getMenuTreeMap()
	if err != nil {
		return nil, err
	}
	menuMenuInfoList := treeMap[0]
	for i := 0; i < len(menuMenuInfoList); i++ {
		err = getBaseChildrenList(menuMenuInfoList[i], treeMap)
	}
	out.Data = menuMenuInfoList
	return out, err
}

func (a *menu) AddMenuAuthority(in *model.AddMenuAuthorityInfoRequest) (err error) {
	data, err := a.iAuthority.Find(in.AuthorityId)
	if err != nil {
		log.Error("AddMenuAuthority error", err)
		return err
	}
	if data.AuthorityId <= 0 {
		return errors.RoleNotExist.Error()
	}
	var authorityMenu []*entity.AuthorityMenu
	for i := range in.Menus {
		authorityMenu = append(authorityMenu, &entity.AuthorityMenu{
			MenuId:      in.Menus[i].ID,
			AuthorityId: data.AuthorityId,
		})
	}
	err = a.iAuthorityMenu.SetMenuAuthority(in.AuthorityId, authorityMenu)
	return err
}

func (a *menu) GetMenuAuthority(in *model.GetMenuAuthorityRequest) (*model.GetMenuAuthorityResponse, error) {
	var (
		err               error
		out               = &model.GetMenuAuthorityResponse{}
		authorityMenuList []*entity.AuthorityMenu
		authorityIds      []int64
	)
	authorityIds = append(authorityIds, in.AuthorityId)
	//获取角色菜单
	if authorityMenuList, err = a.iAuthorityMenu.FindByAuthorityIds(authorityIds); err != nil {
		log.Error("获取角色菜单失败!", err)
		return nil, err
	}
	var menuIds []int64
	for i := range authorityMenuList {
		menuIds = append(menuIds, authorityMenuList[i].MenuId)
	}
	//获取菜单
	menuMenuInfoList, err := getMenuListByMenuIds(menuIds)
	if err != nil {
		return nil, err
	}
	out.Data = menuMenuInfoList
	return out, err
}

func (a *menu) Create(in *model.MenuCreateRequest) error {
	var (
		err  error
		data *entity.Menu
	)
	if in.ParentId == nil {
		return errors.ParameterErr.Error()
	}
	parameter := &model.MenuInfo{
		Name: in.Name,
	}
	if data, err = a.iMenu.FindByParameter(parameter); err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		log.Error(err)
		return err
	}
	if data.ID != 0 {
		return errors.DuplicateDataError.Error()
	}
	c := buildMenu(in)
	_, err = a.iMenu.Create(c)
	return err
}

func (a *menu) Update(in *model.MenuUpdateRequest) error {
	var (
		dict = make(map[string]interface{})
		err  error
	)
	if in.ParentId == nil {
		return errors.ParameterErr.Error()
	}
	data, err := a.iMenu.Find(in.ID)
	if err != nil || data.ID <= 0 {
		log.WithFields(log.Fields{
			"id": in.ID,
		}).Error("修改菜单异常或未找到数据")
		return errors.ParameterErr.Error()
	}
	if data.Name != in.Name {
		if !errors.Is(a.iMenu.IsExistSameName(in.ID, in.Name), gorm.ErrRecordNotFound) {
			return errors.MenuExitsSameName.Error()
		}
	}
	dict["path"] = in.Path
	dict["name"] = in.Name
	dict["menu_level"] = in.MenuLevel
	dict["hidden"] = in.Hidden
	dict["component"] = in.Component
	dict["sort"] = in.Sort
	dict["active_name"] = in.ActiveName
	dict["keep_alive"] = in.KeepAlive
	dict["default_menu"] = in.DefaultMenu
	dict["close_tab"] = in.CloseTab
	dict["icon"] = in.Icon
	dict["title"] = in.Title
	dict["parent_id"] = *in.ParentId
	dict["permission"] = in.Permission
	return a.iMenu.Update(in.ID, dict)
}

func (a *menu) Delete(in *model.MenuDeleteRequest) (err error) {
	p := &model.MenuInfo{
		ParentId: in.ID,
	}
	_, err = a.iMenu.FindByParameter(p)
	if err != nil {
		err = a.iAuthorityMenu.DeleteByMenuId(in.ID)
		err = a.iMenu.Delete(in.ID)
	} else {
		log.WithFields(log.Fields{
			"id": in.ID,
		}).Error("删除菜单异常或存在子菜单")
		return errors.MenuExistSubmenu.Error()
	}
	return err
}

func (a *menu) List(in *model.MenuListRequest) (*model.MenuListResponse, error) {
	var (
		err   error
		total int
		list  []*entity.Menu
		out   = &model.MenuListResponse{}
	)

	if total, list, err = a.iMenu.List(in); err != nil {
		return nil, err
	}

	out.Total = total
	out.Data = model.MenusEntityToDto(list)

	return out, err
}

func getMenuListByMenuIds(menuIds []int64) ([]*model.MenuInfo, error) {
	menuList, err := Menu.iMenu.FindByIds(menuIds)
	if err != nil {
		log.Error("获取菜单失败!", err)
		return nil, err
	}
	allMenus := model.MenusEntityToDto(menuList)
	treeMap := make(map[int64][]*model.MenuInfo)
	for _, v := range allMenus {
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
	}
	menuMenuInfoList := treeMap[0]
	for i := 0; i < len(menuMenuInfoList); i++ {
		err = getBaseChildrenList(menuMenuInfoList[i], treeMap)
	}
	return menuMenuInfoList, err
}

func getMenuTreeMap() (map[int64][]*model.MenuInfo, error) {
	var (
		err      error
		menuList []*entity.Menu
		treeMap  = make(map[int64][]*model.MenuInfo)
		allMenus []*model.MenuInfo
	)
	menuList, err = Menu.iMenu.GetBaseMenuTreeMap()
	if err != nil {
		log.Error("获取getMenuTreeMap失败!", err)
		return nil, err
	}
	allMenus = model.MenusEntityToDto(menuList)
	treeMap = make(map[int64][]*model.MenuInfo)
	for _, v := range allMenus {
		treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
	}
	return treeMap, err
}

func getBaseChildrenList(menu *model.MenuInfo, treeMap map[int64][]*model.MenuInfo) (err error) {
	menu.Children = treeMap[menu.ID]
	for i := 0; i < len(menu.Children); i++ {
		err = getBaseChildrenList(menu.Children[i], treeMap)
	}
	return err
}

func buildMenu(in *model.MenuCreateRequest) *entity.Menu {
	return &entity.Menu{

		MenuLevel: in.MenuLevel,

		ParentId: *in.ParentId,

		Path: in.Path,

		Name: in.Name,

		Hidden: in.Hidden,

		Component: in.Component,

		Sort: in.Sort,

		ActiveName: in.ActiveName,

		KeepAlive: in.KeepAlive,

		DefaultMenu: in.DefaultMenu,

		Title: in.Title,

		Icon: in.Icon,

		CloseTab: in.CloseTab,

		CreatedAt: time.Now().Unix(),

		UpdatedAt:  time.Now().Unix(),
		Permission: in.Permission,
	}
}
